package generation.methods;

import java.util.SortedSet;

import moplayer.ComplexMidiAnalyzer;
import moplayer.MidiAnalyzer;
import moplayer.MoMidiUtils;
import moplayer.ScaleFiller;

public final class ComplexMarkov {
	
	// A map for our musical pitches
	int[] targetNotes = { 67, 69, 60, 62, 64 };
	// A multidimensional array representing our markov matrix
	double[][] markovMatrix = { 
			{ 0.5,  0.0,  0.5,  0.0,  0.0 },
			{ 0.0,  0.25, 0.25, 0.25, 0.25 },
			{ 0.25, 0.25, 0.25, 0.25, 0.0 },
			{ 0.5,  0.0,  0.5,  0.0,  0.0 }, 
			{ 1.0/3.0, 0.0,  0.0,  1.0/3.0, 1.0/3.0 } 
	};
	// The seed for generating output
	int seed; // checking that our map says 64 is at index 2
	// The output as an index value
	int output; // there are no outputs yet
	boolean isFirstTime;
	
	String[] originNotesSet;
	int[] window = new int[2];
	BasicMarkov basicMarkov;
	
	public ComplexMarkov() {
		this.isFirstTime = true;
		this.seed = 2;
		this.output = 0;
	}
	
	public ComplexMarkov(int[] targetNotes, String[] originNotesSet, double[][] matrix){
		this();
		this.targetNotes = targetNotes;
		this.originNotesSet = originNotesSet;
		this.markovMatrix = matrix;
		this.basicMarkov = MidiAnalyzer.analyzeMIDI("midis/otherside.mid", "13");
	}
	
	public int getNextPitch(int previousPitch) {
		int result = 0;
		if(isFirstTime){
			result = targetNotes[seed];
			window[0] = 60;
			window[1] = 64;
			isFirstTime = false;
		} else {
			// Retrieve a random number between 0.0 and 1.0
			double choice = Math.random();
			
			// The current sum of weightings left to right
			double currentSum = 0.0;
			
			int index = MoMidiUtils.getIndex(originNotesSet, MoMidiUtils.indexize(window[0], window[1]));
			if(index == -1){
				result = this.basicMarkov.getNextPitch(window[1]);
				//result = 70;
			} else {
				while(output < markovMatrix.length){
					
					currentSum += markovMatrix[index][output];
					if (choice <= currentSum) {
						break; // break when we have chosen the right number
					}
					output++;
				}
				
				result = targetNotes[output];
				//seed = output;
				output = 0;
			}
			window[0] = window[1];
			window[1] = result;
		}
		
		return result;
	}
	
	public int[] getTargetNotes() {
		return targetNotes;
	}

	public static void main(String[] args) {
		ComplexMarkov bm = ComplexMidiAnalyzer.analyzeMIDI("midis/garcon.mid", "3");
		int[] notes = bm.getTargetNotes();
		ScaleFiller f = new ScaleFiller();
		System.out.println(f.getClosestScale(notes));
	}

	public int[] getScale() {
		int[] notes = this.getTargetNotes();
		ScaleFiller f = new ScaleFiller();
		String closestScale = f.getClosestScale(notes);
		System.out.println("Closest scale = " + closestScale);
		SortedSet<Integer> sortedSet = f.scales.get(closestScale);
		int[] result = new int[sortedSet.size()];
		int i = 0;
		for (Integer note : sortedSet) {
			result[i++] = note;
		}
		return result;
	}
}
